home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / oci8.php < prev    next >
PHP Script  |  2004-10-01  |  29KB  |  900 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: James L. Pine <jlp@valinux.com>                              |
  17. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: oci8.php,v 1.67 2004/06/24 15:24:56 danielc Exp $
  21.  
  22.  
  23. // be aware...  OCIError() only appears to return anything when given a
  24. // statement, so functions return the generic DB_ERROR instead of more
  25. // useful errors that have to do with feedback from the database.
  26.  
  27.  
  28. require_once 'DB/common.php';
  29.  
  30. /**
  31.  * Database independent query interface definition for PHP's Oracle 8
  32.  * call-interface extension.
  33.  *
  34.  * Definitely works with versions 8 and 9 of Oracle.
  35.  *
  36.  * @package  DB
  37.  * @version  $Id: oci8.php,v 1.67 2004/06/24 15:24:56 danielc Exp $
  38.  * @category Database
  39.  * @author   James L. Pine <jlp@valinux.com>
  40.  */
  41. class DB_oci8 extends DB_common
  42. {
  43.     // {{{ properties
  44.  
  45.     var $connection;
  46.     var $phptype, $dbsyntax;
  47.     var $manip_query = array();
  48.     var $prepare_types = array();
  49.     var $autoCommit = 1;
  50.     var $last_stmt = false;
  51.  
  52.     /**
  53.      * stores the $data passed to execute() in the oci8 driver
  54.      *
  55.      * Gets reset to array() when simpleQuery() is run.
  56.      *
  57.      * Needed in case user wants to call numRows() after prepare/execute
  58.      * was used.
  59.      *
  60.      * @var array
  61.      * @access private
  62.      */
  63.     var $_data = array();
  64.  
  65.     // }}}
  66.     // {{{ constructor
  67.  
  68.     function DB_oci8()
  69.     {
  70.         $this->DB_common();
  71.         $this->phptype = 'oci8';
  72.         $this->dbsyntax = 'oci8';
  73.         $this->features = array(
  74.             'prepare' => false,
  75.             'pconnect' => true,
  76.             'transactions' => true,
  77.             'limit' => 'alter'
  78.         );
  79.         $this->errorcode_map = array(
  80.             1 => DB_ERROR_CONSTRAINT,
  81.             900 => DB_ERROR_SYNTAX,
  82.             904 => DB_ERROR_NOSUCHFIELD,
  83.             921 => DB_ERROR_SYNTAX,
  84.             923 => DB_ERROR_SYNTAX,
  85.             942 => DB_ERROR_NOSUCHTABLE,
  86.             955 => DB_ERROR_ALREADY_EXISTS,
  87.             1400 => DB_ERROR_CONSTRAINT_NOT_NULL,
  88.             1407 => DB_ERROR_CONSTRAINT_NOT_NULL,
  89.             1476 => DB_ERROR_DIVZERO,
  90.             1722 => DB_ERROR_INVALID_NUMBER,
  91.             2289 => DB_ERROR_NOSUCHTABLE,
  92.             2291 => DB_ERROR_CONSTRAINT,
  93.             2292 => DB_ERROR_CONSTRAINT,
  94.             2449 => DB_ERROR_CONSTRAINT,
  95.         );
  96.     }
  97.  
  98.     // }}}
  99.     // {{{ connect()
  100.  
  101.     /**
  102.      * Connect to a database and log in as the specified user.
  103.      *
  104.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  105.      * @param $persistent (optional) whether the connection should
  106.      *        be persistent
  107.      *
  108.      * @return int DB_OK on success, a DB error code on failure
  109.      */
  110.     function connect($dsninfo, $persistent = false)
  111.     {
  112.         if (!DB::assertExtension('oci8')) {
  113.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  114.         }
  115.         $this->dsn = $dsninfo;
  116.  
  117.         $connect_function = $persistent ? 'OCIPLogon' : 'OCILogon';
  118.  
  119.         if ($dsninfo['hostspec']) {
  120.             $conn = @$connect_function($dsninfo['username'],
  121.                                        $dsninfo['password'],
  122.                                        $dsninfo['hostspec']);
  123.         } elseif ($dsninfo['username'] || $dsninfo['password']) {
  124.             $conn = @$connect_function($dsninfo['username'],
  125.                                        $dsninfo['password']);
  126.         } else {
  127.             $conn = false;
  128.         }
  129.         if ($conn == false) {
  130.             $error = OCIError();
  131.             $error = (is_array($error)) ? $error['message'] : null;
  132.             return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  133.                                      null, $error);
  134.         }
  135.         $this->connection = $conn;
  136.         return DB_OK;
  137.     }
  138.  
  139.     // }}}
  140.     // {{{ disconnect()
  141.  
  142.     /**
  143.      * Log out and disconnect from the database.
  144.      *
  145.      * @return bool true on success, false if not connected.
  146.      */
  147.     function disconnect()
  148.     {
  149.         $ret = @OCILogOff($this->connection);
  150.         $this->connection = null;
  151.         return $ret;
  152.     }
  153.  
  154.     // }}}
  155.     // {{{ simpleQuery()
  156.  
  157.     /**
  158.      * Send a query to oracle and return the results as an oci8 resource
  159.      * identifier.
  160.      *
  161.      * @param $query the SQL query
  162.      *
  163.      * @return int returns a valid oci8 result for successful SELECT
  164.      * queries, DB_OK for other successful queries.  A DB error code
  165.      * is returned on failure.
  166.      */
  167.     function simpleQuery($query)
  168.     {
  169.         $this->_data = array();
  170.         $this->last_query = $query;
  171.         $query = $this->modifyQuery($query);
  172.         $result = @OCIParse($this->connection, $query);
  173.         if (!$result) {
  174.             return $this->oci8RaiseError();
  175.         }
  176.         if ($this->autoCommit) {
  177.             $success = @OCIExecute($result,OCI_COMMIT_ON_SUCCESS);
  178.         } else {
  179.             $success = @OCIExecute($result,OCI_DEFAULT);
  180.         }
  181.         if (!$success) {
  182.             return $this->oci8RaiseError($result);
  183.         }
  184.         $this->last_stmt=$result;
  185.         // Determine which queries that should return data, and which
  186.         // should return an error code only.
  187.         return DB::isManip($query) ? DB_OK : $result;
  188.     }
  189.  
  190.     // }}}
  191.     // {{{ nextResult()
  192.  
  193.     /**
  194.      * Move the internal oracle result pointer to the next available result
  195.      *
  196.      * @param a valid oci8 result resource
  197.      *
  198.      * @access public
  199.      *
  200.      * @return true if a result is available otherwise return false
  201.      */
  202.     function nextResult($result)
  203.     {
  204.         return false;
  205.     }
  206.  
  207.     // }}}
  208.     // {{{ fetchInto()
  209.  
  210.     /**
  211.      * Fetch a row and insert the data into an existing array.
  212.      *
  213.      * Formating of the array and the data therein are configurable.
  214.      * See DB_result::fetchInto() for more information.
  215.      *
  216.      * @param resource $result    query result identifier
  217.      * @param array    $arr       (reference) array where data from the row
  218.      *                            should be placed
  219.      * @param int      $fetchmode how the resulting array should be indexed
  220.      * @param int      $rownum    the row number to fetch
  221.      *
  222.      * @return mixed DB_OK on success, null when end of result set is
  223.      *               reached or on failure
  224.      *
  225.      * @see DB_result::fetchInto()
  226.      * @access private
  227.      */
  228.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  229.     {
  230.         if ($rownum !== null) {
  231.             return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  232.         }
  233.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  234.             $moredata = @OCIFetchInto($result,$arr,OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  235.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE &&
  236.                 $moredata)
  237.             {
  238.                 $arr = array_change_key_case($arr, CASE_LOWER);
  239.             }
  240.         } else {
  241.             $moredata = OCIFetchInto($result,$arr,OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  242.         }
  243.         if (!$moredata) {
  244.             return null;
  245.         }
  246.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  247.             $this->_rtrimArrayValues($arr);
  248.         }
  249.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  250.             $this->_convertNullArrayValuesToEmpty($arr);
  251.         }
  252.         return DB_OK;
  253.     }
  254.  
  255.     // }}}
  256.     // {{{ freeResult()
  257.  
  258.     /**
  259.      * Free the internal resources associated with $result.
  260.      *
  261.      * @param $result oci8 result identifier
  262.      *
  263.      * @return bool true on success, false if $result is invalid
  264.      */
  265.     function freeResult($result)
  266.     {
  267.         return @OCIFreeStatement($result);
  268.     }
  269.  
  270.     /**
  271.      * Free the internal resources associated with a prepared query.
  272.      *
  273.      * @param $stmt oci8 statement identifier
  274.      *
  275.      * @return bool true on success, false if $result is invalid
  276.      */
  277.     function freePrepared($stmt)
  278.     {
  279.         if (isset($this->prepare_types[(int)$stmt])) {
  280.             unset($this->prepare_types[(int)$stmt]);
  281.             unset($this->manip_query[(int)$stmt]);
  282.         } else {
  283.             return false;
  284.         }
  285.         return true;
  286.     }
  287.  
  288.     // }}}
  289.     // {{{ numRows()
  290.  
  291.     function numRows($result)
  292.     {
  293.         // emulate numRows for Oracle.  yuck.
  294.         if ($this->options['portability'] & DB_PORTABILITY_NUMROWS &&
  295.             $result === $this->last_stmt)
  296.         {
  297.             $countquery = 'SELECT COUNT(*) FROM ('.$this->last_query.')';
  298.             $save_query = $this->last_query;
  299.             $save_stmt = $this->last_stmt;
  300.  
  301.             if (count($this->_data)) {
  302.                 $smt = $this->prepare('SELECT COUNT(*) FROM ('.$this->last_query.')');
  303.                 $count = $this->execute($smt, $this->_data);
  304.             } else {
  305.                 $count =& $this->query($countquery);
  306.             }
  307.  
  308.             if (DB::isError($count) ||
  309.                 DB::isError($row = $count->fetchRow(DB_FETCHMODE_ORDERED)))
  310.             {
  311.                 $this->last_query = $save_query;
  312.                 $this->last_stmt = $save_stmt;
  313.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  314.             }
  315.             return $row[0];
  316.         }
  317.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  318.     }
  319.  
  320.     // }}}
  321.     // {{{ numCols()
  322.  
  323.     /**
  324.      * Get the number of columns in a result set.
  325.      *
  326.      * @param $result oci8 result identifier
  327.      *
  328.      * @return int the number of columns per row in $result
  329.      */
  330.     function numCols($result)
  331.     {
  332.         $cols = @OCINumCols($result);
  333.         if (!$cols) {
  334.             return $this->oci8RaiseError($result);
  335.         }
  336.         return $cols;
  337.     }
  338.  
  339.     // }}}
  340.     // {{{ errorNative()
  341.  
  342.     /**
  343.      * Get the native error code of the last error (if any) that occured
  344.      * on the current connection.  This does not work, as OCIError does
  345.      * not work unless given a statement.  If OCIError does return
  346.      * something, so will this.
  347.      *
  348.      * @return int native oci8 error code
  349.      */
  350.     function errorNative()
  351.     {
  352.         if (is_resource($this->last_stmt)) {
  353.             $error = @OCIError($this->last_stmt);
  354.         } else {
  355.             $error = @OCIError($this->connection);
  356.         }
  357.         if (is_array($error)) {
  358.             return $error['code'];
  359.         }
  360.         return false;
  361.     }
  362.  
  363.     // }}}
  364.     // {{{ prepare()
  365.  
  366.     /**
  367.      * Prepares a query for multiple execution with execute().
  368.      *
  369.      * With oci8, this is emulated.
  370.      *
  371.      * prepare() requires a generic query as string like <code>
  372.      *    INSERT INTO numbers VALUES (?, ?, ?)
  373.      * </code>.  The <kbd>?</kbd> characters are placeholders.
  374.      *
  375.      * Three types of placeholders can be used:
  376.      *   + <kbd>?</kbd>  a quoted scalar value, i.e. strings, integers
  377.      *   + <kbd>!</kbd>  value is inserted 'as is'
  378.      *   + <kbd>&</kbd>  requires a file name.  The file's contents get
  379.      *                     inserted into the query (i.e. saving binary
  380.      *                     data in a db)
  381.      *
  382.      * Use backslashes to escape placeholder characters if you don't want
  383.      * them to be interpreted as placeholders.  Example: <code>
  384.      *    "UPDATE foo SET col=? WHERE col='over \& under'"
  385.      * </code>
  386.      *
  387.      * @param string $query query to be prepared
  388.      * @return mixed DB statement resource on success. DB_Error on failure.
  389.      */
  390.     function prepare($query)
  391.     {
  392.         $tokens   = preg_split('/((?<!\\\)[&?!])/', $query, -1,
  393.                                PREG_SPLIT_DELIM_CAPTURE);
  394.         $binds    = count($tokens) - 1;
  395.         $token    = 0;
  396.         $types    = array();
  397.         $newquery = '';
  398.  
  399.         foreach ($tokens as $key => $val) {
  400.             switch ($val) {
  401.                 case '?':
  402.                     $types[$token++] = DB_PARAM_SCALAR;
  403.                     unset($tokens[$key]);
  404.                     break;
  405.                 case '&':
  406.                     $types[$token++] = DB_PARAM_OPAQUE;
  407.                     unset($tokens[$key]);
  408.                     break;
  409.                 case '!':
  410.                     $types[$token++] = DB_PARAM_MISC;
  411.                     unset($tokens[$key]);
  412.                     break;
  413.                 default:
  414.                     $tokens[$key] = preg_replace('/\\\([&?!])/', "\\1", $val);
  415.                     if ($key != $binds) {
  416.                         $newquery .= $tokens[$key] . ':bind' . $token;
  417.                     } else {
  418.                         $newquery .= $tokens[$key];
  419.                     }
  420.             }
  421.         }
  422.  
  423.         $this->last_query = $query;
  424.         $newquery = $this->modifyQuery($newquery);
  425.         if (!$stmt = @OCIParse($this->connection, $newquery)) {
  426.             return $this->oci8RaiseError();
  427.         }
  428.         $this->prepare_types[(int)$stmt] = $types;
  429.         $this->manip_query[(int)$stmt] = DB::isManip($query);
  430.         return $stmt;
  431.     }
  432.  
  433.     // }}}
  434.     // {{{ execute()
  435.  
  436.     /**
  437.      * Executes a DB statement prepared with prepare().
  438.      *
  439.      * @param resource  $stmt  a DB statement resource returned from prepare()
  440.      * @param mixed  $data  array, string or numeric data to be used in
  441.      *                      execution of the statement.  Quantity of items
  442.      *                      passed must match quantity of placeholders in
  443.      *                      query:  meaning 1 for non-array items or the
  444.      *                      quantity of elements in the array.
  445.      * @return int returns an oci8 result resource for successful
  446.      * SELECT queries, DB_OK for other successful queries.  A DB error
  447.      * code is returned on failure.
  448.      * @see DB_oci::prepare()
  449.      */
  450.     function &execute($stmt, $data = array())
  451.     {
  452.         if (!is_array($data)) {
  453.             $data = array($data);
  454.         }
  455.  
  456.         $this->_data = $data;
  457.  
  458.         $types =& $this->prepare_types[(int)$stmt];
  459.         if (count($types) != count($data)) {
  460.             $tmp =& $this->raiseError(DB_ERROR_MISMATCH);
  461.             return $tmp;
  462.         }
  463.  
  464.         $i = 0;
  465.         foreach ($data as $key => $value) {
  466.             if ($types[$i] == DB_PARAM_MISC) {
  467.                 /*
  468.                  * Oracle doesn't seem to have the ability to pass a
  469.                  * parameter along unchanged, so strip off quotes from start
  470.                  * and end, plus turn two single quotes to one single quote,
  471.                  * in order to avoid the quotes getting escaped by
  472.                  * Oracle and ending up in the database.
  473.                  */
  474.                 $data[$key] = preg_replace("/^'(.*)'$/", "\\1", $data[$key]);
  475.                 $data[$key] = str_replace("''", "'", $data[$key]);
  476.             } elseif ($types[$i] == DB_PARAM_OPAQUE) {
  477.                 $fp = @fopen($data[$key], 'rb');
  478.                 if (!$fp) {
  479.                     $tmp =& $this->raiseError(DB_ERROR_ACCESS_VIOLATION);
  480.                     return $tmp;
  481.                 }
  482.                 $data[$key] = fread($fp, filesize($data[$key]));
  483.                 fclose($fp);
  484.             }
  485.             if (!@OCIBindByName($stmt, ':bind' . $i, $data[$key], -1)) {
  486.                 $tmp = $this->oci8RaiseError($stmt);
  487.                 return $tmp;
  488.             }
  489.             $i++;
  490.         }
  491.         if ($this->autoCommit) {
  492.             $success = @OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS);
  493.         } else {
  494.             $success = @OCIExecute($stmt, OCI_DEFAULT);
  495.         }
  496.         if (!$success) {
  497.             $tmp = $this->oci8RaiseError($stmt);
  498.             return $tmp;
  499.         }
  500.         $this->last_stmt = $stmt;
  501.         if ($this->manip_query[(int)$stmt]) {
  502.             $tmp = DB_OK;
  503.         } else {
  504.             $tmp =& new DB_result($this, $stmt);
  505.         }
  506.         return $tmp;
  507.     }
  508.  
  509.     // }}}
  510.     // {{{ autoCommit()
  511.  
  512.     /**
  513.      * Enable/disable automatic commits
  514.      *
  515.      * @param $onoff true/false whether to autocommit
  516.      */
  517.     function autoCommit($onoff = false)
  518.     {
  519.         $this->autoCommit = (bool)$onoff;;
  520.         return DB_OK;
  521.     }
  522.  
  523.     // }}}
  524.     // {{{ commit()
  525.  
  526.     /**
  527.      * Commit transactions on the current connection
  528.      *
  529.      * @return DB_ERROR or DB_OK
  530.      */
  531.     function commit()
  532.     {
  533.         $result = @OCICommit($this->connection);
  534.         if (!$result) {
  535.             return $this->oci8RaiseError();
  536.         }
  537.         return DB_OK;
  538.     }
  539.  
  540.     // }}}
  541.     // {{{ rollback()
  542.  
  543.     /**
  544.      * Roll back all uncommitted transactions on the current connection.
  545.      *
  546.      * @return DB_ERROR or DB_OK
  547.      */
  548.     function rollback()
  549.     {
  550.         $result = @OCIRollback($this->connection);
  551.         if (!$result) {
  552.             return $this->oci8RaiseError();
  553.         }
  554.         return DB_OK;
  555.     }
  556.  
  557.     // }}}
  558.     // {{{ affectedRows()
  559.  
  560.     /**
  561.      * Gets the number of rows affected by the last query.
  562.      * if the last query was a select, returns 0.
  563.      *
  564.      * @return number of rows affected by the last query or DB_ERROR
  565.      */
  566.     function affectedRows()
  567.     {
  568.         if ($this->last_stmt === false) {
  569.             return $this->oci8RaiseError();
  570.         }
  571.         $result = @OCIRowCount($this->last_stmt);
  572.         if ($result === false) {
  573.             return $this->oci8RaiseError($this->last_stmt);
  574.         }
  575.         return $result;
  576.     }
  577.  
  578.     // }}}
  579.     // {{{ modifyQuery()
  580.  
  581.     function modifyQuery($query)
  582.     {
  583.         // "SELECT 2+2" must be "SELECT 2+2 FROM dual" in Oracle
  584.         if (preg_match('/^\s*SELECT/i', $query) &&
  585.             !preg_match('/\sFROM\s/i', $query)) {
  586.             $query .= ' FROM dual';
  587.         }
  588.         return $query;
  589.     }
  590.  
  591.     // }}}
  592.     // {{{ modifyLimitQuery()
  593.  
  594.     /**
  595.      * Emulate the row limit support altering the query
  596.      *
  597.      * @param string $query The query to treat
  598.      * @param int    $from  The row to start to fetch from
  599.      * @param int    $count The offset
  600.      * @return string The modified query
  601.      *
  602.      * @author Tomas V.V.Cox <cox@idecnet.com>
  603.      */
  604.     function modifyLimitQuery($query, $from, $count, $params = array())
  605.     {
  606.         // Let Oracle return the name of the columns instead of
  607.         // coding a "home" SQL parser
  608.  
  609.         if (count($params)) {
  610.             $result = $this->prepare("SELECT * FROM ($query) "
  611.                                      . 'WHERE NULL = NULL');
  612.             $tmp =& $this->execute($result, $params);
  613.         } else {
  614.             $q_fields = "SELECT * FROM ($query) WHERE NULL = NULL";
  615.  
  616.             if (!$result = @OCIParse($this->connection, $q_fields)) {
  617.                 $this->last_query = $q_fields;
  618.                 return $this->oci8RaiseError();
  619.             }
  620.             if (!@OCIExecute($result, OCI_DEFAULT)) {
  621.                 $this->last_query = $q_fields;
  622.                 return $this->oci8RaiseError($result);
  623.             }
  624.         }
  625.  
  626.         $ncols = OCINumCols($result);
  627.         $cols  = array();
  628.         for ( $i = 1; $i <= $ncols; $i++ ) {
  629.             $cols[] = '"' . OCIColumnName($result, $i) . '"';
  630.         }
  631.         $fields = implode(', ', $cols);
  632.         // XXX Test that (tip by John Lim)
  633.         //if (preg_match('/^\s*SELECT\s+/is', $query, $match)) {
  634.         //    // Introduce the FIRST_ROWS Oracle query optimizer
  635.         //    $query = substr($query, strlen($match[0]), strlen($query));
  636.         //    $query = "SELECT /* +FIRST_ROWS */ " . $query;
  637.         //}
  638.  
  639.         // Construct the query
  640.         // more at: http://marc.theaimsgroup.com/?l=php-db&m=99831958101212&w=2
  641.         // Perhaps this could be optimized with the use of Unions
  642.         $query = "SELECT $fields FROM".
  643.                  "  (SELECT rownum as linenum, $fields FROM".
  644.                  "      ($query)".
  645.                  '  WHERE rownum <= '. ($from + $count) .
  646.                  ') WHERE linenum >= ' . ++$from;
  647.         return $query;
  648.     }
  649.  
  650.     // }}}
  651.     // {{{ nextId()
  652.  
  653.     /**
  654.      * Returns the next free id in a sequence
  655.      *
  656.      * @param string  $seq_name  name of the sequence
  657.      * @param boolean $ondemand  when true, the seqence is automatically
  658.      *                           created if it does not exist
  659.      *
  660.      * @return int  the next id number in the sequence.  DB_Error if problem.
  661.      *
  662.      * @internal
  663.      * @see DB_common::nextID()
  664.      * @access public
  665.      */
  666.     function nextId($seq_name, $ondemand = true)
  667.     {
  668.         $seqname = $this->getSequenceName($seq_name);
  669.         $repeat = 0;
  670.         do {
  671.             $this->expectError(DB_ERROR_NOSUCHTABLE);
  672.             $result =& $this->query("SELECT ${seqname}.nextval FROM dual");
  673.             $this->popExpect();
  674.             if ($ondemand && DB::isError($result) &&
  675.                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
  676.                 $repeat = 1;
  677.                 $result = $this->createSequence($seq_name);
  678.                 if (DB::isError($result)) {
  679.                     return $this->raiseError($result);
  680.                 }
  681.             } else {
  682.                 $repeat = 0;
  683.             }
  684.         } while ($repeat);
  685.         if (DB::isError($result)) {
  686.             return $this->raiseError($result);
  687.         }
  688.         $arr = $result->fetchRow(DB_FETCHMODE_ORDERED);
  689.         return $arr[0];
  690.     }
  691.  
  692.     /**
  693.      * Creates a new sequence
  694.      *
  695.      * @param string $seq_name  name of the new sequence
  696.      *
  697.      * @return int  DB_OK on success.  A DB_Error object is returned if
  698.      *              problems arise.
  699.      *
  700.      * @internal
  701.      * @see DB_common::createSequence()
  702.      * @access public
  703.      */
  704.     function createSequence($seq_name)
  705.     {
  706.         $seqname = $this->getSequenceName($seq_name);
  707.         return $this->query("CREATE SEQUENCE ${seqname}");
  708.     }
  709.  
  710.     // }}}
  711.     // {{{ dropSequence()
  712.  
  713.     /**
  714.      * Deletes a sequence
  715.      *
  716.      * @param string $seq_name  name of the sequence to be deleted
  717.      *
  718.      * @return int  DB_OK on success.  DB_Error if problems.
  719.      *
  720.      * @internal
  721.      * @see DB_common::dropSequence()
  722.      * @access public
  723.      */
  724.     function dropSequence($seq_name)
  725.     {
  726.         $seqname = $this->getSequenceName($seq_name);
  727.         return $this->query("DROP SEQUENCE ${seqname}");
  728.     }
  729.  
  730.     // }}}
  731.     // {{{ oci8RaiseError()
  732.  
  733.     /**
  734.      * Gather information about an error, then use that info to create a
  735.      * DB error object and finally return that object.
  736.      *
  737.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  738.      *                          manually raising an error
  739.      * @return object  DB error object
  740.      * @see DB_common::errorCode()
  741.      * @see DB_common::raiseError()
  742.      */
  743.     function oci8RaiseError($errno = null)
  744.     {
  745.         if ($errno === null) {
  746.             $error = @OCIError($this->connection);
  747.             return $this->raiseError($this->errorCode($error['code']),
  748.                                      null, null, null, $error['message']);
  749.         } elseif (is_resource($errno)) {
  750.             $error = @OCIError($errno);
  751.             return $this->raiseError($this->errorCode($error['code']),
  752.                                      null, null, null, $error['message']);
  753.         }
  754.         return $this->raiseError($this->errorCode($errno));
  755.     }
  756.  
  757.     // }}}
  758.     // {{{ getSpecialQuery()
  759.  
  760.     /**
  761.      * Returns the query needed to get some backend info
  762.      * @param string $type What kind of info you want to retrieve
  763.      * @return string The SQL query string
  764.      */
  765.     function getSpecialQuery($type)
  766.     {
  767.         switch ($type) {
  768.             case 'tables':
  769.                 return 'SELECT table_name FROM user_tables';
  770.             default:
  771.                 return null;
  772.         }
  773.     }
  774.  
  775.     // }}}
  776.     // {{{ tableInfo()
  777.  
  778.     /**
  779.      * Returns information about a table or a result set.
  780.      *
  781.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  782.      * is a table name.
  783.      *
  784.      * NOTE: flags won't contain index information.
  785.      *
  786.      * @param object|string  $result  DB_result object from a query or a
  787.      *                                string containing the name of a table
  788.      * @param int            $mode    a valid tableInfo mode
  789.      * @return array  an associative array with the information requested
  790.      *                or an error object if something is wrong
  791.      * @access public
  792.      * @internal
  793.      * @see DB_common::tableInfo()
  794.      */
  795.     function tableInfo($result, $mode = null)
  796.     {
  797.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  798.             $case_func = 'strtolower';
  799.         } else {
  800.             $case_func = 'strval';
  801.         }
  802.  
  803.         if (is_string($result)) {
  804.             /*
  805.              * Probably received a table name.
  806.              * Create a result resource identifier.
  807.              */
  808.             $result = strtoupper($result);
  809.             $q_fields = 'SELECT column_name, data_type, data_length, '
  810.                         . 'nullable '
  811.                         . 'FROM user_tab_columns '
  812.                         . "WHERE table_name='$result' ORDER BY column_id";
  813.  
  814.             $this->last_query = $q_fields;
  815.  
  816.             if (!$stmt = @OCIParse($this->connection, $q_fields)) {
  817.                 return $this->oci8RaiseError(DB_ERROR_NEED_MORE_DATA);
  818.             }
  819.             if (!@OCIExecute($stmt, OCI_DEFAULT)) {
  820.                 return $this->oci8RaiseError($stmt);
  821.             }
  822.  
  823.             $i = 0;
  824.             while (@OCIFetch($stmt)) {
  825.                 $res[$i]['table'] = $case_func($result);
  826.                 $res[$i]['name']  = $case_func(@OCIResult($stmt, 1));
  827.                 $res[$i]['type']  = @OCIResult($stmt, 2);
  828.                 $res[$i]['len']   = @OCIResult($stmt, 3);
  829.                 $res[$i]['flags'] = (@OCIResult($stmt, 4) == 'N') ? 'not_null' : '';
  830.  
  831.                 if ($mode & DB_TABLEINFO_ORDER) {
  832.                     $res['order'][$res[$i]['name']] = $i;
  833.                 }
  834.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  835.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  836.                 }
  837.                 $i++;
  838.             }
  839.  
  840.             if ($mode) {
  841.                 $res['num_fields'] = $i;
  842.             }
  843.             @OCIFreeStatement($stmt);
  844.  
  845.         } else {
  846.             if (isset($result->result)) {
  847.                 /*
  848.                  * Probably received a result object.
  849.                  * Extract the result resource identifier.
  850.                  */
  851.                 $result = $result->result;
  852.             } else {
  853.                 /*
  854.                  * ELSE, probably received a result resource identifier.
  855.                  * Deprecated.  Here for compatibility only.
  856.                  */
  857.             }
  858.  
  859.             if ($result === $this->last_stmt) {
  860.                 $count = @OCINumCols($result);
  861.  
  862.                 for ($i=0; $i<$count; $i++) {
  863.                     $res[$i]['table'] = '';
  864.                     $res[$i]['name']  = $case_func(@OCIColumnName($result, $i+1));
  865.                     $res[$i]['type']  = @OCIColumnType($result, $i+1);
  866.                     $res[$i]['len']   = @OCIColumnSize($result, $i+1);
  867.                     $res[$i]['flags'] = '';
  868.  
  869.                     if ($mode & DB_TABLEINFO_ORDER) {
  870.                         $res['order'][$res[$i]['name']] = $i;
  871.                     }
  872.                     if ($mode & DB_TABLEINFO_ORDERTABLE) {
  873.                         $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  874.                     }
  875.                 }
  876.  
  877.                 if ($mode) {
  878.                     $res['num_fields'] = $count;
  879.                 }
  880.  
  881.             } else {
  882.                 return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  883.             }
  884.         }
  885.         return $res;
  886.     }
  887.  
  888.     // }}}
  889.  
  890. }
  891.  
  892. /*
  893.  * Local variables:
  894.  * tab-width: 4
  895.  * c-basic-offset: 4
  896.  * End:
  897.  */
  898.  
  899. ?>
  900.